package supermarket;

import guiforms.BuyProductsScreen;
import java.io.File;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Random;
import java.util.Scanner;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import model.Customer;
import model.Product;
import model.ProductPurchase;
import model.Purchase;
import model.Store;
import guiforms.LoginForm;
import guiforms.MainScreen;
import guiforms.ManagerScreen;


/**
 *
 * @author Nicolas Drosos
 */
public class SuperMarket {    
    // O entity manager 
    private static EntityManager em;    
    // Αναγνώστης εισόδου από το πληκτρολόγιο
    private final Scanner keyboardReader;
    // Το όριο πόντων της κάρτας στο οποίο ο πελάτης κερδίζει μια επιταγή
    public static final int CHECK_POINTS_LIMIT = 200;    
    
    public SuperMarket(){        
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("SuperMarketPU");
        // Δημιουργία του Entity Manager
        em = emf.createEntityManager();    
        // Δημιουργία ενός "αναγνώστη" από το πληκτρολόγιο
        keyboardReader = new Scanner(System.in, "Cp1253");      
    }

    public EntityManager getEm() {
        return em;
    }
    
    // Καθαρίζει όλους τους πίνακες της ΒΔ
    private void clearDB(){        
        em.getTransaction().begin();
        try {
            Query q=em.createQuery("DELETE FROM ProductPurchase pp");
            q.executeUpdate();                        
            q=em.createQuery("DELETE FROM Product p");
            q.executeUpdate();            
            q=em.createQuery("DELETE FROM Purchase pu");
            q.executeUpdate();                                    
            q=em.createQuery("DELETE FROM Store s");
            q.executeUpdate();            
            q=em.createQuery("DELETE FROM Customer c");
            q.executeUpdate();
            q=em.createQuery("DELETE FROM Checks c");
            q.executeUpdate();
            
            em.getTransaction().commit();
        } catch (Exception e) {
            e.printStackTrace();
            em.getTransaction().rollback();
        } 
    }
    
    /**
     * Δημιουργεί 10 προϊόντα και 2 καταστήματα. Στη συνέχεια καθορίζει τα προϊόντα που 
     * εμπορεύεται κάθε κατάστημα και τα αποθηκεύει στη ΒΔ.
     */
    public void createStoresAndProducts(){
        // αρχικοποίηση transaction
        em.getTransaction().begin();
        try {
            // Δημιουργία 10 διαφορετικών αντικειμένων Product. Η κατάσταση των Product entities
            // είναι 'Νέο' καθώς δεν έχουν γίνει ακόμα managed από τον entity manager
            // στο persistence context 
            Product spagheti=new Product("Μακαρόνια No7", "11111", 10, 1.20f);
            Product nescafe=new Product("Καφές 500gr", "22222", 12, 3.20f);
            Product cleaning=new Product("Απορρυπαντικό Liquid 5lt", "33333", 20, 15.50f);
            Product oliveOil=new Product("Λάδι 5lt", "44444", 6, 10.30f);
            Product bath=new Product("Bath oil", "55555", 4, 6.50f);
            Product tigani=new Product("Τηγάνι 30cm", "666666", 30, 20.0f);
            Product pet=new Product("Pet food", "77777", 6, 9.45f);
            Product beer=new Product("Beer 500mlx6", "88888", 5, 7.66f);
            Product alcoholDrink=new Product("Alcohol drink", "99999", 50, 36.77f);
            Product chocolateCake=new Product("Chocolate Cake", "00000", 2, 5.20f);
            Customer cust1 = new Customer(0,"Name1","Surname1","111-111",199);
            Customer cust2 = new Customer(0,"Name2","Surname2","222-222",1);
            cust1.setPassword("1111");
            cust1.setAddress("Address1");
            cust1.setCreditcard("1111-111111-1111");
            cust2.setPassword("2222");
            em.persist(cust1);
            em.persist(cust2);
            // Δημιουργία 2 διαφορετικών αντικειμένων Store. 
            Store abAlimou = new Store("AB Αλίμου", "Καλαμακίου 120, Άλιμος");
            Store abFalirou = new Store("AB Φαλήρου", "Ποσειδώνος 300, Παλαιό Φάληρο"); 
            
            /**
             * Για να ορίσουμε τα προϊόντα που εμπορεύεται ένα κατάστημα, δημιουργούμε μια
             * λίστα και προσθέτουμε τα προϊόντα που θέλουμε σε αυτή. Στη συνέχεια θέτουμε τη
             * λίστα αυτή στο αντικείμενο Store. Η σχέση Store-Product είναι many-to-many, 
             * δηλαδή αφενός το Store έχει μια λίστα με Products, αφετέρου το Store έχει μια
             * λίστα με Stores.Επίσης έχουμε ορίσει CascadeType.ALL στη λίστα productList της 
             * κλάσης Store. Αυτό σημαίνει ότι όλες οι αλλαγές άρα και η δημιουργία ενός 
             * αντικειμένου Store θα προκαλέσει τη δημιουργία και των αντίστοιχων αντικειμένων 
             * Product που βρίσκονται στη λίστα του.
             * 
             */            
            List<Product> alimouList = new ArrayList<>();
            alimouList.add(spagheti);alimouList.add(nescafe);alimouList.add(cleaning);
            alimouList.add(oliveOil);alimouList.add(bath);alimouList.add(tigani);
            alimouList.add(pet);alimouList.add(chocolateCake);
            abAlimou.setProductList(alimouList);
            em.persist(abAlimou);
                        
            // κάνουμε το ίδιο και για το άλλο κατάστημα
            List<Product> falirouList = new ArrayList<>();
            falirouList.add(spagheti);falirouList.add(nescafe);falirouList.add(cleaning);
            falirouList.add(oliveOil);falirouList.add(bath);falirouList.add(tigani);
            falirouList.add(beer);falirouList.add(alcoholDrink);
            abFalirou.setProductList(falirouList);
            em.persist(abFalirou);
                         
            /**
             * Κάνοντας commit το transaction θα δημιουργηθούν οι αντίστοιχες εγγραφές Store και
             * Product στη ΒΔ ενώ τα αντίστοιχα αντικείμενα θα γίνουν managed.
             */
            em.getTransaction().commit();
        } catch (Exception e) {
            e.printStackTrace();
            em.getTransaction().rollback();
        } 
    }
    
    /**
     * Δημιουργεί το κεντρικό μενού της εφαρμογής
     */
    public void displayMainMenu() {
        System.out.println("Καλωσήλθατε στην εφαρμογή κονσόλας του super market");                       
        File xmlFile = new File("C:\\temp\\purchases.xml");
        PurchaseXMLManager purchaseXMLWriter = new PurchaseXMLManager(xmlFile);
        String choice;
        do {
            System.out.println("**** Κεντρικό μενού ****");
            System.out.println("1. Νέος πελάτης");
            System.out.println("2. Αγορά προϊόντων");
            System.out.println("3. Ενημέρωση ταχυδρομικής διεύθυνσης");
            System.out.println("4. Εξαγωγή αγορών σε XML");
            System.out.println("5. Μέσο ποσό αγορών");
            System.out.println("6. Έξοδος");
            System.out.println("7. Debug");
            System.out.print("Επιλέξτε > "); 
            choice = keyboardReader.nextLine();
            switch (choice) {
                case "1":                  
                  createNewCustomer();
                  break;
                case "2":
                  purchaseProducts();
                  break;    
                case "3":
                  updateCustomer();
                  break; 
                case "4":     
                    exportPurchases(purchaseXMLWriter);                       
                    break;
                case "5":                  
                  System.out.println("MO: "+purchaseXMLWriter.calculateAveragePurchaseAmount());
                  break;    
                case "6":
                  System.out.println("ΕΞΟΔΟΣ");
                  break;
                case "7":
                  System.out.println("Loading...");
                  runform();  
                  break;
                default:
                  System.err.println ("Λανθασμένη επιλογή! Προσπαθήστε ξανά...");
                  break;
            }
        }while (!choice.equals("6"));
        keyboardReader.close();
    }
    
    /**
     * Καταχωρεί ένα νέο πελάτη στη ΒΔ με βάση στοιχεία που διαβάζονται από το πληκτρολόγιο.
     */
    public void createNewCustomer(){
        System.out.println ("Καταχώρηση νέου πελάτη");
        // Δημιουργούμε ένα νέο αντικείμενο Customer και καθώς ζητάμε τις διάφορες πληροφορίες
        // από το χρήστη τις θέτουμε στο αντικείμενο αυτό.
        Customer c = new Customer();               
        System.out.print("Όνομα πελάτη: ");
        // Θέτει το όνομα του πελάτη
        c.setFirstName(keyboardReader.nextLine());
        System.out.print("Επώνυμο πελάτη: ");
        // Θέτει το επώνυμο του πελάτη
        c.setLastName(keyboardReader.nextLine());        
        System.out.print("Password: ");
        c.setPassword(keyboardReader.nextLine()); 
        // Ακολουθεί σχετική ερώτηση για καταχώρηση του προαιρετικού πεδίου διεύθυνση. 
        // Για την αποφυγή λανθασμένης εισόδου από το χρήστη χρησιμοποιούμε μια επαναληπτική 
        // διαδικασία η οποία δε θα τερματίσει παρά μόνο όταν λάβει αποδεκτή πληροφορία από το
        // χρήστη, που στην περίπτωση αυτή είναι οι χαρακτήρες 'Ν' για ΝΑΙ ή 'Ο' για ΌΧΙ'.        
        String choice;
        boolean blockExit;
        do {
            System.out.print("Θέλετε να καταχωρήσετε ταχυδρομική διεύθυνση;(Ν/Ο): ");
            choice = keyboardReader.nextLine();
            switch (choice) {
                // αν δοθεί 'Ν' (ΝΑΙ) τότε διαβάζεται η διεύθυνση του πελάτη και τίθεται στο
                // αντικείμενο Customer c.
                case "N": case "Ν":
                    System.out.print("Διεύθυνση: ");
                    c.setAddress(keyboardReader.nextLine());                    
                    blockExit = false;                    
                    break;
                // αν δοθεί 'Ο' (ΟΧΙ) τότε η διαδικασία συνεχίζει χωρίς την καταχώρηση διεύθυνσης
                case "O": case "Ο":
                    System.out.println("Συνέχεια χωρίς ταχυδρομική διεύθυνση!");
                    blockExit = false;
                    break;                
                // Αν δε δοθεί ούτε 'Ν' ούτε 'Ο' εμφανίζεται σχετικό μήνυμα λάθους και μπλοκάρεται
                // η έξοδος από το επαναληπτικό block κώδικα
                default:
                  System.err.println ("Λανθασμένη επιλογή! Προσπαθήστε ξανά...");
                  blockExit = true;
                  break;
            }
        }while (blockExit);
        
        // Χρησιμοποιώντας τη βοηθητική μέθοδο randInt παράγει 2 τυχαίους αριθμούς μεταξύ
        // 100 και 999 για να εξασφαλίσουμε ότι τα 2 τμήματα του κωδικού της κάρτας θα είναι
        // τριψήφια.
        String firstTriplet = Integer.toString(randInt(100,999));
        String secondTriplet = Integer.toString(randInt(100,999));
        // Στη συνέχεια αφού έχουμε μετατρέψει τους 2 αριθμούς σε αλφαριθμητικά τα ενώνουμε 
        // με τη διαχωριστική - και έτσι δημιουργούμε τον τυχαία παραγόμενο κωδικό κάρτας και τον
        // θέτουμε στο αντικείμενο Customer c.
        String cardNumber = firstTriplet+"-"+secondTriplet;
        c.setPointsCardNumber(cardNumber);
        // Αρχικοποιούμε τους διαθέσιμους πόντους και πλήθος επιταγών στο 0.
        c.setAvailablePoints(0);
        c.setChecksno(0);         
        // Αποθηκεύουμε το αντικείμενο Customer c στη ΒΔ.
        em.getTransaction().begin();
        try {
            em.persist(c);            
            em.getTransaction().commit();
            System.out.println("Επιτυχής Δημιουργία Πελάτη!");
            System.out.println("Ο αριθμός της κάρτας σας είναι: "+cardNumber);
            System.out.println(" ");
        } catch (Exception e) {
            e.printStackTrace();
            em.getTransaction().rollback();
        } 
    }
    
    /**
    * Επιστρέφει ένα ψευδο-τυχαίο αριθμό μεταξύ min και max.    * 
    * @param min Η ελάχιστη τιμή
    * @param max Η μέγιστη τιμή η οποία πρέπει να είναι μεγαλύτερη από τη Min.
    * @return Ακέραιο μεταξύ min και max.    * 
    */
    private int randInt(int min, int max) {       
       Random rand = new Random();       
       int randomNum = rand.nextInt((max - min) + 1) + min;
       return randomNum;
    }
    
    /**
     * Υλοποιεί το σενάριο αγοράς προϊόντων.
     */
    public void purchaseProducts(){
        // Αρχικά καλεί τη μέθοδο findCustomerByCard η οποία ζητάει από το χρήστη τον αριθμό
        // της κάρτας πόντων, βρίσκει τον πελάτη στη βάση και επιστρέφει το managed αντικείμενο
        // του πελάτη.
        Customer c = findCustomerByCard();   
        // Αν βρέθηκε πελάτης
        if (c!= null){               
            // Αρχικοποιεί το αντικείμενο purchase με την τρέχουσα ημερομηνία και ώρα και τον
            // πελάτη που πραγματοποιεί την αγορά.
            Purchase purchase = new Purchase(Calendar.getInstance().getTime(), c);
            System.out.println("Καλωσήλθατε κ/κα "+c.getLastName());
            
            // Tο κατάστημα από το οποίο επιλέγει ο χρήστης να κάνει τις αγορές του. Μέσω της 
            // selectStore() ζητείται από το χρήστη να επιλέξει ένα από τα διαθέσιμα καταστήματα 
            // και επιστρέφεται το επιλεγμένο κατάστημα. 
            Store selectedStore=selectStore();
            purchase.setStore(selectedStore);
            System.out.println("Επιλέξατε το κατάστημα: "+ selectedStore.getName());
            
            // Στη λίστα αυτή αποθηκεύονται αντικείμενα ProductPurchase, δηλαδή αντικείμενα
            // που περιέχουν προϊόντα που θα επιλέξει ο πελάτης και τις αντίστοιχες ποσότητες.
            // Μέσω της selectProducts ο πελάτης με μια επαναληπτική διαδικασία επιλέγει όλα τα
            // προϊόντα που θέλει να συμπεριληφθούν στην αγορά του. Η selectProducts επίσης
            // θέτει το συνολικό ποσό και πόντους στο αντικείμενο purchase.
            List<ProductPurchase> productPurchaseList = selectProducts(selectedStore, purchase);
            // Η λίστα με τα προϊόντα τίθεται στο αντικείμενο purchase, και έτσι λόγω του cascade
            // στη one-to-many σχέση του purchase με το productPurchase όταν αποηκευτεί το purchase
            // θα αποθηκευτούν και τα αντίστοιχα productPurchase αντικείμενα.
            purchase.setProductPurchaseList(productPurchaseList);
            System.out.println("Επιτυχής επιλογή προϊόντων!");            
            System.out.println("Σύνολο: "+purchase.getAmount());            
            System.out.println("Πόντοι που κερδίσατε σήμερα: "+purchase.getPointsEarned());
            
            // Ζητάει από τον πελάτη να επιλέξει τρόπο πληρωμής και πραγματοποιεί την πληρωμή.
            makePayment(purchase, c);
            // Ζητάει από τον πελάτη να επιλέξει τρόπο παράδοσης και το αποθηκεύει στο αντικείμενο
            // purchase.
            selectDeliveryWay(c, purchase);
            
            // Αποθηκεύει το αντικείμενο purchase καθώς και τα productPurchase (μέσω του cascade)
            // στη ΒΔ
            em.getTransaction().begin();
            try {
                em.persist(purchase);            
                em.getTransaction().commit();
            } catch (Exception e) {
                e.printStackTrace();
                em.getTransaction().rollback();
            } 
        }   
        else {
            System.err.println("Δε βρέθηκε πελάτης με τον αριθμό κάρτας!");
        }
    }
    
    /**
     * Ζητάει από το χρήστη τον κωδικό της καρτας πόντων και επιστρέφει τον πελάτη που έχει την 
     * κάρτα με το συγκεκριμένο κωδικό. Αν δε βρεθεί πελάτης επιστρέφει null.
     * @return Τον πελάτη στον οποίο αντιστοιχεί ο αριθμός κάρτας που διαβάζεται από το πληκτρολόγιο
     * ή null σε περίπτωση που δε βρεθεί.
     */
    private Customer findCustomerByCard(){
        System.out.print("Δώστε αριθμό κάρτας: ");        
        // Χρησιμοποιούμε το έτοιμο namedQuery που έχει παραχθεί αυτόματα από το Netbeans
        TypedQuery<Customer> findCustomerQuery =
            em.createNamedQuery("Customer.findByPointsCardNumber", Customer.class);
        // Ως παράμετρο στο Query θέτουμε τον αριθμό κάρτας που διαβάζουμε από το πληκτρολόγιο
        findCustomerQuery.setParameter("pointsCardNumber", keyboardReader.nextLine());
        List<Customer> customerResults = findCustomerQuery.getResultList();
        System.out.print(" ");        
        // Αν δε βρεθεί κανένα αποτέλεσμα είτε βρεθούν περισσότερα θεωρούμε ότι ο πελάτης δε βρέθηκε.
        // Θα μπορούσαμε να διακρίνουμε περιπτώσεις έτσι ώστε να διασφαλίσουμε κατά την καταχώρηση
        // ότι δε θα καταχωρηθεί πελάτης με αριθμό κάρτας που υπάρχει στη βάση. Επειδή όμως
        // ο αριθμός δημιουργείται τυχαία και για ελάττωση της πολυπλοκότητας θεωρούμε ότι το
        // να παραχθεί ίδιο αριθμός κάρτας είναι εξαιρετικά σπάνιο και έτσι δεν το αντιμετωπίζουμε.
        if (customerResults.size() != 1){            
            return null;
        }
        else {
            // Εφόσον βρεθεί μοναδικό αποτέλεσμα το επιστρέφουμε.
            Customer c = customerResults.get(0);  
            return c;
        }        
    }
    
    /**
     * Παρουσιάζει στο χρήστη τα διαθέσιμα καταστήματα (από τη ΒΔ) και ζητάει από το χρήστη να 
     * επιλέξει. Το επιλεγμένο κατάστημα επιστρέφεται.
     * @return Το καταστημα που επιλεγει ο χρήστης.
     */
    private Store selectStore(){
        String choice;
        boolean blockExit; 
        // Αναπαριστά το κατάστημα από το οποίο θα επιλέξει ο χρήστης να κάνει τις αγορές του.
        Store selectedStore=null;
        do {
            System.out.println("*** Επιλογή καταστήματος ***");
            TypedQuery<Store> allStoresQuery = em.createNamedQuery("Store.findAll", Store.class);
            List<Store> storeResults = allStoresQuery.getResultList();            
            int storeIndex = 1;
            for (Store s:storeResults){
                System.out.println(storeIndex+". "+s.getName()+" - "+s.getAddress());
                storeIndex++;
            }            
            System.out.print("Επιλέξτε > "); 
            choice = keyboardReader.nextLine();  
            try {
                int choiceInt = Integer.parseInt(choice);
                if (choiceInt >= 1 && choiceInt <= storeResults.size()) {
                    selectedStore = storeResults.get(Integer.valueOf(choice).intValue()-1);
                    blockExit = false;
                }
                else {
                    System.err.println("Λανθασμένη επιλογή");
                    blockExit = true;
               }
            } catch(NumberFormatException e) { 
                System.err.println("Λανθασμένη επιλογή");
                blockExit = true;
            }
        }while (blockExit);  
        return selectedStore;
    }
    
    /**
     * Παρουσιάζει στο χρήστη τη λίστα των προϊόντων που έχει το κατάστημα store και ζητάει από
     * το χρήστη να επιλέξει με μια επαναληπτική διαδικασία τα προϊόντα που θα συμπεριληφθούν
     * στην αγορά του (purchase). 
     * @param store Το καταστημα από το οποίο έχει επιλέξει να ψωνίσει ο χρήστης
     * @param purchase Η αγορά που βρίσκεται σε εξέλιξη
     * @return  Επισρέφει λίστα με αντικείμενα ProductPurchase, δηλαδή αντικείμενα 
     * που περιέχουν τα προϊόντα που θα επιλέξει ο πελάτης και τις αντίστοιχες ποσότητες.
     */
    private List<ProductPurchase> selectProducts(Store store, Purchase purchase){
        // Στη λίστα αυτή θα αποθηκευτούν αντικείμενο ProductPurchase, δηλαδή αντικείμενα
        // που περιέχουν προϊόντα που θα επιλέξει ο πελάτης και τις αντίστοιχες ποσότητες.
        List<ProductPurchase> productPurchaseList = new ArrayList<>();
                        
        float totalPrice=0.0f;
        int totalPointsEarned=0;
        // Αναπαριστά την επιλογή ολοκλήρωσης της διαδικασίας.
        String completeChoice;
        boolean blockExit=true;
        String choice;
        do {
           System.out.println("*** Επιλογή προϊόντων ***");
            List<Product> storeProducts = store.getProductList();
            int productIndex = 1;
            for (Product p:storeProducts){
                System.out.println(productIndex+". "+p.getName()+" - "+p.getPrice()+" euros");
                productIndex++;
            }
            // Ως επιλογή ολοκλήρωσης θεωρούμε τον επόμενο αριθμό από το τελευταίο προϊόν. Για 
            // παράδειγμα αν η λίστα έχει 8 προϊόντα (1-8) τότε θεωρούμε ως επιλογή ολοκκλήρωσης
            // και τερματισμού της διαδικασίας την επιλογή 9.
            completeChoice = new Integer(storeProducts.size()+1).toString();
            System.out.println(completeChoice+". Ολοκλήρωση");

            System.out.print("Επιλογή > ");
            choice = keyboardReader.nextLine();           
            if (!choice.equalsIgnoreCase(completeChoice)){
                try {
                    int choiceInt = Integer.parseInt(choice);
                    if (choiceInt >= 1 && choiceInt <= storeProducts.size()) {                        
                        Product selectedProduct = storeProducts.get(Integer.valueOf(choice).intValue()-1);
                        System.out.println("Επιλέξατε το προϊόν: "+ selectedProduct.getName());
                        System.out.print("Δώστε ποσότητα: ");
                        int quantity = Integer.valueOf(keyboardReader.nextLine()).intValue();
                        ProductPurchase pp = new ProductPurchase(selectedProduct, purchase, quantity);
                        productPurchaseList.add(pp);
                        // Υπολογίζει την τελική τιμή της αγοράς πολλαπλασιάζοντας την ποσότητα επί
                        // την τιμή κάθε προϊόντος και προσθέτοντας το σύνολο.
                        totalPrice+=quantity*selectedProduct.getPrice();
                        // Παρομοίως υπολογίζει το σύνολο των πόντων της αγοράς
                        totalPointsEarned+=quantity*selectedProduct.getPoints();
                        System.out.println("Τρέχον υπόλοιπο: "+totalPrice);                            
                    }
                    else {
                         System.err.println("Λανθασμένη επιλογή");
                         blockExit = true;
                    }
                } catch(NumberFormatException e) { 
                    System.err.println("Λανθασμένη επιλογή");
                    blockExit = true;
                }
            }
            else {
                if (productPurchaseList.isEmpty()) {
                    System.err.println("Πρέπει να επιλέξετε τουλάχιστον ένα προϊόν!");
                    blockExit = true;
                }
                else {
                    blockExit = false;
                }
            }
        }while (blockExit);  
        purchase.setAmount(totalPrice);
        purchase.setPointsEarned(totalPointsEarned);
        return productPurchaseList;
    }
    
    /**
     * Παρουσιάζει στο χρήστη τις δυνατές επιλογές πληρωμής (Μετρητά - Επιταγή) και ανάλογα με την 
     * επιλογή του χρήστη κάνει τους σχετικούς ελεγχους και πραγματοποιεί την πληρωμή.
     * @param purchase Η αγορά που βρίσκεται σε εξέλιξη 
     * @param c Ο πελάτης
     */
    private void makePayment(Purchase purchase, Customer c){
        boolean blockExit;
        String choice;
        do {
            System.out.println("*** Επιλογή τρόπου πληρωμής ***");
            System.out.println("1. Μετρητά");                
            System.out.println("2. Επιταγή");                
            System.out.print("Επιλέξτε > "); 
            choice = keyboardReader.nextLine();                
            switch (choice) {
                case "1":                  
                    System.out.println("Πληρωμή με μετρητά!");                        
                    blockExit = false;
                    break;                    
                case "2":
                    System.out.println("Πληρωμή με επιταγή!");
                    // Αν ο χρήστης δεν έχει κερδισμένες επιταγές δεν επιτρέπεται να πληρώσει
                    // με αυτό τον τρόπο.
                    if (c.getChecksno() == 0){
                       System.err.println("Δεν έχετε κερδίσει καμία επιταγή!");
                       blockExit = true;
                    }
                    else {                           
                        // Αν έχει τότε μειώνει τις επιταγές κατά 1
                        c.setChecksno(c.getChecksno()-1);                            
                        blockExit = false;
                    }
                    break;     
                default:
                    System.err.println ("Λανθασμένη επιλογή!");
                    blockExit = true;
                    break;
            }
        }while (blockExit);
        
        // Σε κάθε περίπτωση όταν ο έλεγχος περάσει από το παραπάνω επαναληπτικό block, θα πρέπει 
        // να γίνει η πληρωμή.
        System.out.println("Η συναλλαγή σας ολοκληρώθηκε!");
        System.out.println("Ημερομηνία: "+purchase.getDatetime());
        System.out.println("Συνολικό ποσό: "+purchase.getAmount());    
        // Έλεγχος αν ο πελάτης δικαιούται επιταγή με βάση τους διαθέσιμους + τους κερδισμένους
        // από αυτή την αγορά πόντους
        if (c.getAvailablePoints()+purchase.getPointsEarned() > CHECK_POINTS_LIMIT) {
            // Με βάση τους κερδισμένους πόντους υπολογίζει πόσες επιταγές δικαιούται ο πελάτης
            int noOfChecksEarned = (c.getAvailablePoints()+purchase.getPointsEarned())/CHECK_POINTS_LIMIT;
            System.out.println("Συγχαρητήρια κερδίσατε "+ noOfChecksEarned +
                    " επιταγές!");
            // Αφαιρεί τους πόντους που αντιστοιχούν στην επιταγή και ενημερώνει τους διαθέσιμους
            c.setAvailablePoints(c.getAvailablePoints()+purchase.getPointsEarned()-noOfChecksEarned*CHECK_POINTS_LIMIT);
            // Αυξάνει τις κερδισμένες επιταγές
            c.setChecksno(c.getChecksno()+noOfChecksEarned);
            System.out.println("Υπόλοιπο πόντων: "+c.getAvailablePoints());
            System.out.println("Σύνολο επιταγών: "+c.getChecksno());
        }
        else { // Αν δε δικαιούται επιγαγή ενημερώνει τους διαθέσιμους πόντους
            c.setAvailablePoints(c.getAvailablePoints()+purchase.getPointsEarned());
            System.out.println("Υπόλοιπο πόντων: "+c.getAvailablePoints());
            System.out.println("Σύνολο επιταγών: "+c.getChecksno());
        }
    }
    
    /**
     * Παρουσιάζει στο χρήστη τους δυνατούς τρόπους παραλαβής των προϊόντων (Στο χωρο του πελάτη 
     * ή από το κατάστημα). Για να επιλεχθεί αποστολή στο χώρο του πελάτη θα πρέπει να έχει
     * δηλώσει διεύθυνση.
     * @param c Ο πελάτης
     * @param purchase Η αγορά που βρίσκεται σε εξέλιξη
     */
    private void selectDeliveryWay(Customer c, Purchase purchase){        
        boolean blockExit;        
        do {
            System.out.println("*** Επιλογή τρόπου παράδοσης ***");
            System.out.println("1. Στο χώρο σας");                
            System.out.println("2. Παραλαβή από κατάστημα");                
            System.out.print("Επιλέξτε > "); 
            String choice = keyboardReader.nextLine();                
            switch (choice) {
                case "1":                                          
                    if (c.getAddress() != null){
                        System.out.println("Επιλέξατε παράδοση στο χώρο σας!");
                        System.out.println("Η παράδοση θα γίνει στη διεύθυνση: "+c.getAddress());
                        purchase.setDelivery(true);
                        blockExit = false;
                    }
                    else {
                        System.err.println("Δεν έχετε δηλώσει ταχυδρομική διεύθυνση!");
                        blockExit = true;
                    }                        
                    break;                    
                case "2":
                     System.out.println("Επιλέξατε παραλαβή από κατάστημα!");                         
                     System.out.println("Η παραλαβή θα γίνει από το κατάστημα: "+purchase.getStore().getName());
                     purchase.setDelivery(false);
                     blockExit = false;
                    break;     
                default:
                    System.err.println ("Λανθασμένη επιλογή!");
                    blockExit = true;
                    break;
            }
        }while (blockExit);        
    }
    
    /**
     * Ζητάει από το χρήστη τη διεύθυνση του πελάτη και ενημερώνει το αντικείμενο.
     */
    private void updateCustomer(){
        Customer c = findCustomerByCard();             
        if (c!=null){                        
            System.out.print("Διεύθυνση: ");            
            em.getTransaction().begin();
            try {
                c.setAddress(keyboardReader.nextLine());                                                  
                em.getTransaction().commit();
                System.out.println("Επιτυχής Ενημέρωση Πελάτη!");                
                System.out.println(" ");
            } catch (Exception e) {
                e.printStackTrace();
                em.getTransaction().rollback();
            }            
        }
    }
    
    /**
     * Εξάγει όλες τις αγορές που είναι αποθηκευμένες στη ΒΔ σε αρχείο XML στη θέση C:\temp
     * @param purchaseXMLWriter 
     */
    private void exportPurchases(PurchaseXMLManager purchaseXMLWriter){
        TypedQuery<Purchase> allPurchasesQuery = em.createNamedQuery("Purchase.findAll", Purchase.class);
        List<Purchase> purchaseResults = allPurchasesQuery.getResultList();                    
        purchaseXMLWriter.writeXML(purchaseResults);
        System.out.println ( "Το αρχείο XML δημιουργήθηκε με επιτυχία στο C:\\temp" );                    
        try {
            em.getTransaction().begin();
            for (Purchase p:purchaseResults){
                em.remove(p);
            }
            em.getTransaction().commit();
            System.out.println("Επιτυχής Διαγραφή συναλλαγών!");            
            System.out.println(" ");
        } catch (Exception e) {
            e.printStackTrace();
            em.getTransaction().rollback();
        }   
    }
    
    private void runform(){
    LoginForm form1 = new guiforms.LoginForm();
    form1.setVisible(true);
    } 

    
        
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
    SuperMarket sm = new SuperMarket();         
    //Καθαρισμός Βάσης Δεδομένων
        //sm.clearDB();
        //Δημιουργία καταστημάτων και προϊόντων
        //sm.createStoresAndProducts();
        // Προβολή βασικού μενού επιλογών
        //sm.displayMainMenu();
        
        
        
        LoginForm mainform = new guiforms.LoginForm();
        mainform.setVisible(true);
                       
                
    }    
}
